﻿using SoundEngine3;
using SoundEngine3.AudioProcessing;
using SoundEngine3.AudioProcessing.Filters;
using SoundEngine3.DspPlugins;
using SoundEngine3.DspPlugins.Meta;
using System;
using System.Collections.Generic;
using ZquenceStudio3.Core;
using ZquenceStudio3.Core.DspPlugins;
using ZquenceStudio3.DspPlugins;

namespace ZquenceStudio.DefaultDspPlugins.Effects
{
    public class FlangerDescription : IDspPlugin
    {
        public DspPluginInfo GetDspPluginInfo()
        {
            return new DspPluginInfo("Flanger", DspType.Effect);
        }

        public BaseDspPluginInstance CreateDsp(ZquenceStudio3Context context, DspPluginInfo info)
        {
            return new Flanger(context, info);
        }
    }

    public class Flanger : CoreDspEffectPlugin
    {
        FilterFlanger[] flangers;

        /// <summary>
        /// Get or set the flanger delta time.
        /// </summary>
        public double Flanging
        {
            get { return flangers[0].DelayTime; }
            set
            {
                foreach (var flanger in flangers)
                {
                    flanger.DelayTime = value;
                }
            }
        }

        /// <summary>
        /// Get or set the flanger buffer length.
        /// </summary>
        public int Buffer
        {
            get { return flangers[0].BufferLength; }
            set
            {
                foreach (var flanger in flangers)
                {
                    flanger.BufferLength = value;
                }
            }
        }

        /// <summary>
        /// Get or set the feedback.
        /// </summary>
        public double Feedback
        {
            get { return flangers[0].Feedback; }
            set
            {
                foreach (var flanger in flangers)
                {
                    flanger.Feedback = value;
                }
            }
        }

        /// <summary>
        /// Get or set the feedback.
        /// </summary>
        public double Output
        {
            get { return flangers[0].Output; }
            set
            {
                foreach (var flanger in flangers)
                {
                    flanger.Output = value;
                }
            }
        }

        public Flanger(ZquenceStudio3Context application, DspPluginInfo info)
            : base(application, info)
        {
            flangers = new FilterFlanger[1];
            flangers[0] = new FilterFlanger(SoundEngineContext.BufferSize);

            flangers[0].DelayTime = 1;
            flangers[0].Feedback = 0.5;
            flangers[0].Output = 0.8;
            flangers[0].BufferLength = 512;

            CreateParameters();

            SupportAudioProcessing = true;
        }

        private void CreateParameters()
        {
            int index = 0;

            // Flanging.
            ParameterPropertiesDirect flanging = new ParameterPropertiesDirect(this);
            flanging.Label = "Flanging";
            flanging.DirectGet += delegate() { return Flanging; };
            flanging.DirectSet += delegate(double value) { Flanging = value; };
            flanging.MinValue = 0.001;
            flanging.MaxValue = 1.0;
            AddParameter(flanging);

            // Buffer.
            ParameterPropertiesDirect buffer = new ParameterPropertiesDirect(this);
            buffer.Label = "Buffer";
            buffer.DirectGet += delegate() { return Buffer; };
            buffer.DirectSet += delegate(double value) { Buffer = (int)value; };
            buffer.MinValue = 1;
            buffer.MaxValue = 1024;
            buffer.IsInteger = true;
            AddParameter(buffer);

            // Feedback.
            ParameterPropertiesDirect feedback = new ParameterPropertiesDirect(this);
            feedback.Label = "Feedback";
            feedback.DirectGet += delegate() { return Feedback; };
            feedback.DirectSet += delegate(double value) { Feedback = value; };
            feedback.MinValue = 0.001;
            feedback.MaxValue = 0.9;
            AddParameter(feedback);

            // Output.
            ParameterPropertiesDirect output = new ParameterPropertiesDirect(this);
            output.Label = "Output";
            output.DirectGet += delegate() { return Output; };
            output.DirectSet += delegate(double value) { Output = value; };
            output.MinValue = 0;
            output.MaxValue = 1;
            AddParameter(output);
        }
        
        public override Version Version
        {
            get { return DspPluginInfo.DefaultVersion; }
        }

        public override string PluginInfo
        {
            get { return DspPluginInfo.DefaultPluginInfo; }
        }
        
        public override void Process(BaseAudioBuffer input, BaseAudioBuffer output)
        {
            int length = input.Channels.Length;
            for (int i = 0; i < length; i++)
            {
                Channel channelIn = input.Channels[i];
                Channel channelOut = output.Channels[i];

                flangers[i].ProcessTime(channelIn.Samples, channelOut.Samples);
            }
        }
        
        protected override void OnChangeBufferSize(int bufferSize)
        {

        }

        protected override void OnChangeSampleRate(double sampleRate)
        {

        }

        protected override void OnChangeInputChannels(int channels)
        {

        }

        protected override void OnChangeOutputChannels(int channels)
        {
            double feedback = this.Feedback;
            double flanger = this.Flanging;
            int buffer = this.Buffer;
            double output = this.Output;

            flangers = new FilterFlanger[channels];
            for (int i = channels - 1; i >= 0; i--)
            {
                flangers[i] = new FilterFlanger(SoundEngineContext.BufferSize);
            }

            this.Feedback = feedback;
            this.Flanging = flanger;
            this.Buffer = buffer;
            this.Output = output;
        }

        protected override void OnProcessEvents(List<SoundEngine3.MIDI.Meta.MidiMessage> midiMessages)
        {

        }
    }
}
